﻿using System;
using BigfootDNN.Mvc;
using BigfootWeb;
using BigfootWeb.Helpers;

namespace BigfootDNN
{
    public class DnnViewHelper : ViewHelper
    {

        /// <summary>
        /// This is the route information for the current route being executed
        /// </summary>
        private RouteInfo Route;

        /// <summary>
        /// Determines weather this view is being rendered as a partial view
        /// </summary>
        private readonly bool IsRenderPartial;

        /// <summary>
        /// Creates a new view helper for a particular MvcBaseView
        /// </summary>
        /// <param name="route">The current route being executed</param>
        /// <param name="isRenderPartial">Determines weather this view is being rendered as a partial view</param>
        public DnnViewHelper(RouteInfo route, bool isRenderPartial)
            : base(route.App.Request, route.App.Response, route.App.Server)
        {
            this.Route = route;
            this.IsRenderPartial = isRenderPartial;
        }
        
        /// <summary>
        /// Render a partial view onto the page
        /// </summary>
        /// <param name="ViewName">The name of the view within the current controller to render</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderPartial(string ViewName)
        {
            return RenderPartial(Route.Controller, ViewName, null);
        }

        /// <summary>
        /// Render a partial view onto the page
        /// </summary>
        /// <param name="ViewName">The name of the view within the current controller to render</param>
        /// <param name="data">The data to be used as the views model</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderPartial(string ViewName, object data)
        {
            return RenderPartial(Route.Controller, ViewName, data);
        }

        /// <summary>
        /// Render a partial view onto the page only if the specified condition is met
        /// </summary>
        /// <param name="Condition">The condition that must be met in order for the view to be rendered</param>
        /// <param name="ViewName">The name of the view within the current controller to render</param>
        /// <param name="data">The data to be used as the views model</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderPartialIf(bool Condition, string ViewName, object data)
        {
            return Condition ? RenderPartial(ViewName, data) : "";
        }

        /// <summary>
        /// Render a partial view onto the page only if the specified condition is met
        /// </summary>
        /// <param name="Condition">The condition that must be met in order for the view to be rendered</param>
        /// <param name="ControllerName">The name of the controller folder where the view exists</param>
        /// <param name="ViewName">The name of the view within the controller folder specified</param>
        /// <param name="data">The data to be used as the views model</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderPartialIf(bool Condition, string ControllerName, string ViewName, object data)
        {
            return Condition ? RenderPartial(ControllerName, ViewName, data) : "";
        }

        /// <summary>
        /// Render a partial view onto the page.
        /// </summary>
        /// <param name="ControllerName">The name of the controller folder where the view exists</param>
        /// <param name="ViewName">The name of the view within the controller folder</param>
        /// <param name="data">The data to be used as the view model</param>
        /// <returns>The rendered html output of the view</returns>
        public string RenderPartial(string ControllerName, string ViewName, object data)
        {
            try
            {
                var controlPath = RouteHelper.ControlPath(ControllerName, ViewName, Route.App);
                return RenderUserControl(controlPath, data, "Route", Route);
            }
            catch (Exception ex)
            {
                Route.App.HandleException(ex, false);
                var errorViewModel = ErrorViewModel.Create(ex, Route.App.Request.Url.ToString());
                return RenderUserControl(Route.App.ErrorViewPath, errorViewModel);
            }
        }

        /// <summary>
        /// This functions is called from the markup to handle any view error. It has the logic to know weather to output the error to the screen
        /// or in the case of being partially rendered to raise the error to the RenderView function
        /// </summary>
        /// <param name="ex">The exception to be handled</param>
        public void HandleViewError(Exception ex)
        {
            if (ex == null) throw new ArgumentNullException("ex");
            // If it is rendering in partial mode, then render the error.
            if (IsRenderPartial) throw ex;

            Route.App.HandleException(ex, false);
            var errorViewModel = ErrorViewModel.Create(ex, Route.App.Request.Url.ToString());
            Route.App.Response.Write(RenderUserControl(Route.App.ErrorViewPath, errorViewModel));
        }

        
        /// <summary>
        /// Creates a new instance of the UrlHelper class to help you create urls
        /// </summary>
        public UrlHelper Url
        {
            get { return _url ?? (_url = new UrlHelper(Route)); }
        }
        private UrlHelper _url;

        /// <summary>
        /// Creates a unique client id specific to this module instance on the page. This is useful when refering to element ids from javascript as
        /// you might have the same id if the module is added to the page several times. It simply adds an underscore plus the 
        /// module id to the name
        /// </summary>
        /// <param name="id">The id of the element you would like to make unique to the module</param>
        /// <returns>It returns {id}_{ModuleId}</returns>
        public string uid(string id)
        {
            return id + "_" + Route.ModData.ModuleID;
        }
    }
}
